/**
 * @file .
 * @author wangxiaowei0303@163.com
 */


#include <time.h>
#ifdef ENABLE_DEBUG
#include <stdio.h>
#endif

#include <random>

#include <opencv2/core/core_c.h>
#include <opencv2/core/core.hpp>

#include "UniformNoise.h"
#include "../string_util.h"
#include "../opencv_util.h"

/*
 * A_ARG;为 this->a 参数呈现给用户的名称.
 * B_ARG;为 this->b 参数呈现给用户的名称.
 */
#define A_ARG "a"
#define B_ARG "b"

UniformNoise::~UniformNoise()
{
    ;
}

void
UniformNoise::help(std::string &buf) const
{
    buf.append(
        "UniformNoise;为图像增加均匀噪声;支持参数如下:\n"
        A_ARG ";均匀噪声的最低值,默认为: -48.990 \n"
        B_ARG ";均匀噪声的最大值,默认为: 48.990  \n"
    );
    return ;
}

/*
 * 处理不合法的参数名.
 * 这里'不合法的参数名'指的是当前算法不支持的参数.
 */
static void
handleInvalidArg(const char *fun,const char *arg)
{
    std::string err("ERROR;不合法的参数 ");
    err += arg;
    err += " 出现在函数 ";
    err += fun;
    err.push_back('\n');
    throw std::runtime_error(err);
}

void
UniformNoise::set(const char *argname,const char *argval)
{
    if (strEqual(argname,A_ARG))
        this->a = str2double(argval);
    else if (strEqual(argname,B_ARG)) 
        this->b = str2double(argval);
    else 
        handleInvalidArg(__PRETTY_FUNCTION__,argname);
}

const char*
UniformNoise::get(const char *argname,std::string &buf) const
{
    size_t oldsize = buf.size();
    if (strEqual(argname,A_ARG)) 
        addFormat(buf,"%f",this->a); 
    else if (strEqual(argname,B_ARG)) 
        addFormat(buf,"%f",this->b);
    else
        return 0;
    return buf.data() + oldsize;
}

void
UniformNoise::getSupportedArgs(std::vector<std::string> &arglist) const
{
    arglist.push_back(A_ARG);
    arglist.push_back(B_ARG);
    return ;
}

void
UniformNoise::process(cv::Mat &img)
{
    if (img.channels() != 1 || img.depth() != CV_8U) {
        std::string err;
        addFormat(err,
            "ERROR;UniformNoise::process(): 不支持的图像格式;"
            "channels: %d(支持: 1);"
            "depth: %s(支持: CV_8U)\n",
            img.channels(),
            depth2str(img.depth()));
        throw std::runtime_error(err);    
    }

    std::mt19937_64 engine(time(0));
    std::uniform_real_distribution<double> n(a,b);

    cv::Mat noise(img.rows,img.cols,CV_64FC1);
    cv::MatIterator_<double> iter = noise.begin<double>();
    cv::MatIterator_<double> const end = noise.end<double>();
    for (; iter != end; ++iter)
        *iter = n(engine);

    cv::MatIterator_<uchar> imgiter = img.begin<uchar>();
    for (iter = noise.begin<double>(); iter != end; ++iter,++imgiter) {
        long t1 = round(*iter + *imgiter);
        if (t1 < 0)
            *imgiter = 0;
        else if (t1 > 255)
            *imgiter = 255;
        else 
            *imgiter = (uchar)t1;
    }
    return ;
}

NOISE_ALGO_REGISTER("UniformNoise",UniformNoise);



